package sk.ygor.xtemplate;

import java.io.*;
import java.util.Map;
import java.util.HashMap;

/**
 * User: ygor
 * Date: 12.11.2005
 * Time: 21:21:58
 */
public class XTemplate implements Serializable {

    private Block root;
    private Map<String, Object> space;


    public XTemplate(File file) throws XTemplateException {
        space = new HashMap<String, Object>();
        root = new Block("$$$root$$$");
        buildBlock(root, new BlockTokenizer(readFile(file)));
    }

    public XTemplate(String resourceName) throws XTemplateException {
        space = new HashMap<String, Object>();
        root = new Block("$$$root$$$");
        buildBlock(root, new BlockTokenizer(loadResource(resourceName)));
    }

    public void setRoot(String rootBlock) throws XTemplateException {
        root = getBlock(rootBlock);
    }

    public void assign(String name, Object object) {
        space.put(name, object);
    }

    public void parse() throws XTemplateException {
        root.parse(space);
    }

    public void parse(String blockPath) throws XTemplateException {
        getBlock(blockPath).parse(space);
    }

    public String getText() {
        return root.getText(space);
    }

    public String getText(String blockPath) throws XTemplateException {
        return getBlock(blockPath).getText(space);
    }

    private Block getBlock(String blockPath) throws XTemplateException {
        String[] blockNames = blockPath.split("\\.");
        Block block = root;
        for (String blockName: blockNames) {
            block = block.getChildBlock(blockName);
            if (block == null) {
                throw new XTemplateException("Block not found: " + blockPath);
            }
        }
        return block;
    }

    private void buildBlock(Block block, BlockTokenizer tokenizer) throws XTemplateException {
        int counter = 0;
        BlockToken token;
        while ((token = tokenizer.nextToken()) != null) {
            if (token.type == BlockToken.BEGIN) {
                Block subBlock = new Block(token.value);
                block.addPart(subBlock, token.value);
                buildBlock(subBlock, tokenizer);
            } else if (token.type == BlockToken.END) {
                if (block.getName().equals(token.value)) {
                    return;
                } else {
                    throw new XTemplateException("BEGIN and END do not match: " +
                            block.getName() + " : " + token.value);
                }
            } else {
                block.addPart(new Content(token.value), "$$$" + counter++);
            }
        }
    }


    private String readFile(File file) throws XTemplateException {
        try {
            StringBuilder builder = new StringBuilder();
            char[] buffer = new char[1024];
            FileReader reader = new FileReader(file);
            int i;
            while ((i = reader.read(buffer)) != -1) {
                builder.append(buffer, 0, i);
            }
            return builder.toString();
        } catch (IOException e) {
            throw new XTemplateException(e);
        }
    }

    private String loadResource(String resourceName) throws XTemplateException {
        InputStream resource = getClass().getClassLoader().getResourceAsStream(resourceName);
        char[] buffer = new char[1024];
        int i;
        StringBuilder sb = new StringBuilder();
        try {
            InputStreamReader reader = new InputStreamReader(resource);
            while ((i = reader.read(buffer)) != -1) {
                sb.append(buffer, 0, i);
            }
            reader.close();
        } catch (IOException e) {
            throw new XTemplateException(e);
        }
        return sb.toString();

    }

    public String toString() {
        return root.toString();
    }

}
